﻿using System;
using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Security.Cryptography;
using WebSocketSharp;
using System.Security.Authentication;
using System.Collections.Concurrent;

namespace TCommon
{
    public class YoudaoTranslateClient
    {
        private ConcurrentQueue<string> sendQueue = new ConcurrentQueue<string>();
        private bool threadNeedClose = false;

        #region 向外传递数据事件
        public event Action<string> MessageReceived;
        #endregion

        WebSocketSharp.WebSocket Socket;

        /// <summary>
        /// 检查重连线程
        /// </summary>
        Thread _thread;
        bool _isRunning = true;
        /// <summary>
        /// WebSocket连接地址
        /// </summary>
        public string ServerPath { get; set; }

        public YoudaoTranslateClient()
        {
            this._thread = new Thread(new ThreadStart(DoSend));
            this._thread.IsBackground = true;
            this._thread.Start();
            ServerPath = init();
        }
        #region "web socket "
        public void Stop()
        {
            threadNeedClose = true;
            this._thread.Abort();
            this.Socket.Close();
        }


        private void DoSend()
        {
            bool needRetry = false;
            int retryCount = 0;
            string message = string.Empty;
            while (true)
            {
                try
                {
                    if (threadNeedClose)
                        return;

                    if (this.Socket == null || this.Socket.ReadyState == WebSocketState.Closed
                       || this.Socket.ReadyState == WebSocketState.Closing)
                    {
                        Connect();
                    }

                    if (!needRetry)
                    {
                        sendQueue.TryDequeue(out message);
                    }

                    if (!string.IsNullOrEmpty(message))
                    {
                        if (this.Socket.ReadyState == WebSocketState.Open)
                        {
                            this.Socket.Send(message);
                        }
                        else
                        {
                            throw new Exception("websocket connection is not open");
                        }
                    }

                    needRetry = false;
                    retryCount = 0;
                }
                catch (Exception ex)
                {
                    if (needRetry)
                    {
                        if (retryCount < 5)
                        {
                            retryCount++;
                        }
                        else
                        {

                            needRetry = false;
                        }
                    }
                    else
                    {
                        needRetry = true;
                    }

                    Thread.Sleep(1000);
                }

                Thread.Sleep(50);
            }
        }
        #endregion
        /// <summary>
        /// 发送消息
        /// </summary>
        /// <param name="Message"></param>
        public void SendMessage(string Message)
        {
            sendQueue.Enqueue(Message);
        }

        private void Connect()
        {
            if (this.Socket == null)
            {
                try
                {
                    if (this.Socket != null)
                    {
                        this.Socket.OnMessage -= Socket_OnMessage;
                        this.Socket?.Close();
                    }
                }
                catch (Exception)
                {
                    //Nothing to do
                }

                this.Socket = new WebSocketSharp.WebSocket(ServerPath);
                this.Socket.OnMessage += Socket_OnMessage;
                this.Socket.SslConfiguration.EnabledSslProtocols = (SslProtocols)3072;
                Socket.SslConfiguration.ServerCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) =>
                {
                    return true; // If the server certificate is valid.
                    };
                this.Socket.Connect();
            }
        }

        private void Socket_OnMessage(object sender, MessageEventArgs e)
        {
            MessageReceived?.Invoke(e.Data);
        }

        //public async Task startReceiving(ClientWebSocket client)
        //{
        //    while (true)
        //    {
        //        var array = new byte[4096];
        //        var result = await client.ReceiveAsync(new ArraySegment(array), CancellationToken.None);
        //        if (result.MessageType == WebSocketMessageType.Text)
        //        {
        //            string msg = Encoding.UTF8.GetString(array, 0, result.Count);
        //            Console.ForegroundColor = ConsoleColor.DarkBlue;
        //            Console.WriteLine("--> {0}", msg);
        //            Console.ForegroundColor = ConsoleColor.DarkGray;
        //        }
        //    }
        //}

        public string init()
        {
            String from = "en";
            String to = "zh-CHS";
            String appKey = "您的应用ID";
            String appSecret = "您的应用密钥";
            String nonce = Guid.NewGuid().ToString();
            TimeSpan ts = (DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc));
            long millis = (long)ts.TotalMilliseconds;
            String curtime = Convert.ToString(millis / 1000);
            String signStr = appKey + nonce + curtime + appSecret;
            String sign = encrypt(signStr, null);

            String uri = "wss://openapi.youdao.com/stream_speech_trans?appKey=" + appKey + "&salt=" + nonce +
                         "&curtime=" + curtime + "&sign=" + sign +
                         "&version=v1&channel=1&format=wav&signType=v4&rate=16000&from=" + from + "&to=" + to + "&transPattern=stream";
            return uri;
        }

        //加密
        private String encrypt(String strSrc, String encName)
        {
            byte[] bt = Encoding.UTF8.GetBytes(strSrc);
            SHA256 sha256 = SHA256.Create();
            //暂时固定为SHA—256
            //暂时没发现内置的不同hash加密构造方法
            //可以自行编写代替
            if (encName == null || "".Equals(encName))
            {
                encName = "SHA-256";
            }

            byte[] HashData = sha256.ComputeHash(bt);
            StringBuilder oSb = new StringBuilder();

            for (int x = 0; x < HashData.Length; x++)
            {
                //hexadecimal string value
                oSb.Append(HashData[x].ToString("x2"));
            }

            return oSb.ToString();
        }
    }
}
